﻿#define SOS_SCHED_MOD_QZ 1
#define SOS_SCHED_MOD_LZ 2

#if SOS_CONFIG_GENERATOR == 0

	#define SOS_IMPLEMENT_HEAD "sos.c51.h"
	#define SOS_SCHED_MOD SOS_SCHED_MOD_QZ
	#define SOS_RR_TIME 8
	#define SOS_SUPPORT_TASK_NUM 3 	/// 支持的任务数量
	
	#define SOS_DELAY
	#define SOS_TASKSUSPEND
	#define SOS_TASKRESUME
	#define SOS_TIMEDLY

#endif

#include SOS_IMPLEMENT_HEAD

struct TaskCtrlBlock 	/// 任务控制块
{
	unsigned int taskStackTop; 	/// 保存任务的堆栈顶
	unsigned int waitTick; 		/// 任务延时时钟
};

struct TaskCtrlBlock SOS_taskCtrlBlock[SOS_SUPPORT_TASK_NUM+1];

unsigned char SOS_manualStack[TASK_STACK_SIZE(SOS_SUPPORT_TASK_NUM)];	/// 每个任务的分配25个字节的任务堆栈

unsigned char SOS_taskReadyTable = 0x00;		/// 任务运行就绪表
unsigned char SOS_runningTaskId = 0x00;			/// 正在运行的任务

#if SOS_SCHED_MOD == SOS_SCHED_MOD_LZ

unsigned int SOS_rrTimeSize = SOS_RR_TIME;		/// rr算法中时间片大小
unsigned int SOS_rrTimeCount = 0;

#endif

/// 进行任务调度
void TaskSchedule()
{
	
	STACK_PUSH_OP(SP)
	unsigned char nextTaskId = 0x00; 	/// 在现有堆栈上开设新的空间

	SOS_taskCtrlBlock[SOS_runningTaskId].taskStackTop = SP;		/// 将正在运行的任务的堆栈底保存

#if SOS_SCHED_MOD == SOS_SCHED_MOD_QZ

	for(nextTaskId = 0;		/// 进行任务调度
		nextTaskId < SOS_SUPPORT_TASK_NUM && !(SOS_taskReadyTable & (0x01<<nextTaskId));
		nextTaskId++);

#elif SOS_SCHED_MOD == SOS_SCHED_MOD_LZ
	for(nextTaskId = SOS_runningTaskId + 1; nextTaskId < SOS_SUPPORT_TASK_NUM; nextTaskId++)
	{
		if((0x01<<nextTaskId) & SOS_taskReadyTable)
		{
			break;
		}	
	}
	if(nextTaskId >= SOS_SUPPORT_TASK_NUM)
	{
		for(nextTaskId = 0; nextTaskId <= SOS_runningTaskId; nextTaskId++)
		{
			if((0x01<<nextTaskId) & SOS_taskReadyTable)
			{
				break;
			}
		}
	}
		
#endif

	SOS_runningTaskId = nextTaskId ;
	
	CHANGE_SP_TO_RUNNING_TASK(SP,SOS_taskCtrlBlock[SOS_runningTaskId].taskStackTop)

	STACK_POP_OP();
}

/// 操作系统空闲任务
void TaskScheduler()
{
	while(1)
	{
		// PORTB = 0x3f;    /// 发布时该行需注释掉
		TaskSchedule();	/// 反复进行调度
	}
}

SOS_TIMER_INTERRUPT
{
	unsigned char taskId;
	unsigned char reSchedTag = 0;
	for(taskId = 0; taskId < SOS_SUPPORT_TASK_NUM; taskId++)	/// 任务时钟
	{
		if(SOS_taskCtrlBlock[taskId].waitTick)
		{
			SOS_taskCtrlBlock[taskId].waitTick--;
			if(SOS_taskCtrlBlock[taskId].waitTick == 0)	/// 当任务时钟到时,必须是由定时器减时的才行
			{
				SOS_taskReadyTable |= (0x01<<taskId);	/// 使任务在就绪表中置位
				if(SOS_runningTaskId > taskId)
				{
					reSchedTag = 1;
				}
			}
		}
	}

#if SOS_SCHED_MOD == SOS_SCHED_MOD_LZ	

	SOS_rrTimeCount++;
	if(SOS_rrTimeCount == SOS_rrTimeSize)
	{
		SOS_rrTimeCount = 0;
		SOS_TIMER_CLEAR(0)
		TaskSchedule();
	}

#elif SOS_SCHED_MOD == SOS_SCHED_MOD_QZ

	if(reSchedTag == 1)
	{
		SOS_TIMER_CLEAR(0)
		TaskSchedule();
	}	

#endif

	SOS_TIMER_CLEAR(0) // TCNT0=0;

}

#if SOS_DELAY

void SOS_Delay(void)
{
    int i,j;
	for(i = 0; i < 100; i++)
	{
		for(j = 0; j < 300; j++)
		{
			;
		}
	}
}

#endif

#if SOS_TASKSUSPEND

/// 挂起任务
void SOS_TaskSuspend(unsigned char taskId)
{
	SOS_taskCtrlBlock[taskId].waitTick = 0;
	SOS_taskReadyTable &= ~(0x01<<taskId);	/// 从任务就绪表上去除标志位
	if(SOS_runningTaskId == taskId)		/// 当要挂起的任务为当前任务
	{
		TaskSchedule();		/// 从新调度
	}
}

#endif

#if SOS_TASKRESUME

/// 恢复任务 可以让被OSTaskSuspend或 OSTimeDly暂停的任务恢复
void SOS_TaskResume(unsigned char taskId)
{
	SOS_taskReadyTable |= 0x01<<taskId; 	/// 从任务就绪表上重置标志位
	SOS_taskCtrlBlock[taskId].waitTick = 0;	/// 将时间计时设为0,到时
	if(SOS_runningTaskId > taskId)			/// 当要当前任务的优先级低于重置位的任务的优先级
	{
		TaskSchedule();		/// 从新调度
	}
}

#endif

#if SOS_TIMEDLY
void SOS_TimeDly(unsigned int ticks)
{
	if(ticks > 0)
	{
		SOS_taskReadyTable &= ~(0x01<<SOS_runningTaskId);
		SOS_taskCtrlBlock[SOS_runningTaskId].waitTick = ticks;
		TaskSchedule();	/// 重新调度
	}
}
#endif

/// 建立任务
void SOS_TaskCreate(void (*TaskName)(void),unsigned char taskId)
{	
	SOS_TASK_STACK_INIT(TaskName,taskId,SOS_taskCtrlBlock[taskId].taskStackTop,SOS_manualStack);
	// TaskStackInit(Task,TaskID);
	// SOS_taskCtrlBlock[TaskID].SOSTaskStackTop = (unsigned int)Stack; /// 将人工堆栈的栈顶，保存到堆栈的数组中
	SOS_taskReadyTable|=0x01<<taskId;	/// 任务就绪表已经准备好
}

/// 开始任务调度,从最低优先级的任务的开始
void SOS_Start()
{

	SOS_TIMER_INIT(0)
	SOS_TaskCreate(TaskScheduler,SOS_SUPPORT_TASK_NUM);

	SOS_runningTaskId = SOS_SUPPORT_TASK_NUM;
	OS_START_SP_INIT(SP,SOS_taskCtrlBlock[SOS_SUPPORT_TASK_NUM].taskStackTop)
//  OSTaskRunningPrio = OS_TASKS;
// 	SP = SOS_taskCtrlBlock[OS_TASKS].OSTaskStackTop;
}

